package com.mbti.youmore.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mbti.youmore.common.AppProperties;
import com.mbti.youmore.common.exception.PostNotExistException;
import com.mbti.youmore.common.exception.PubBannedWordsException;
import com.mbti.youmore.entity.*;
import com.mbti.youmore.mapper.*;
import com.mbti.youmore.service.PostService;
import com.mbti.youmore.util.BannedWordUtil;
import com.mbti.youmore.util.ProvinceMapperUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author Guqier
 * @description 针对表【t_post】的数据库操作Service实现
 * @createDate 2024-05-08 20:30:45
 */
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post>
        implements PostService {

    @Autowired
    private ChatMapper chatMapper;

    @Autowired
    private CommentMapper commentMapper;// 使用Spring自动注入工具类

    @Autowired
    private UserMapper userMapper;// 使用Spring自动注入工具类

    @Autowired
    private PostMapper postMapper;// 使用Spring自动注入工具类

    @Autowired
    private LikeMapper likeMapper;// 使用Spring自动注入工具类

    @Autowired
    private FollowMapper followMapper;// 使用Spring自动注入工具类

    @Autowired
    private FavoriteMapper favoriteMapper;

    /**
     * 基于用户标签/城市/语言的协同过滤算法
     * @param userId
     * @return 帖子Id列表
     */
    public List<Integer> userCF(int userId) {
        User user = userMapper.selectById(userId);
        Map<String, Integer> cityNumber = new LinkedHashMap<>();
        List<User> users = userMapper.selectList(null);
        List<Integer> postIds = new ArrayList<>();
        List<Favorite> relatedFavorite = new ArrayList<>();


        //初始化所有城市人数为0
        for (Map<String, Object> city : ProvinceMapperUtil.getProvinceMapList()) {
            cityNumber.put((String) city.get("name"), 0);
        }
        //获取距离其他省份的距离
        List<Map<String, Object>> nearestProvinceDistance = ProvinceMapperUtil.getNearestProvinceDistance(user.getUserLocation());
        //获取距离当前用户的城市和附近城市的用户列表
        //如果该用户城市距离当前用户较近，则纳入考虑范围,并且最多将会添加来自不同的几个城市的一百个用户
        Collections.shuffle(users);//打乱列表，增加随机性
        for (User u : users) {
                for (int i = 0; i < AppProperties.NEAREST_PROVINCE_NUM + 1; i++) {
                    if (u.getUserLocation().equals(nearestProvinceDistance.get(i).get("name")) &&
                            (cityNumber.replace(u.getUserLocation(), cityNumber.get(u.getUserLocation())) + 1) <= 100 / AppProperties.NEAREST_PROVINCE_NUM) {
                        List<Favorite> favorites = favoriteMapper.selectList(new LambdaQueryWrapper<Favorite>().eq(Favorite::getUserId, u.getUserId()));
                        //添加推荐用户的收藏夹的帖子id
                        if (!favorites.isEmpty()) {
                            cityNumber.replace(u.getUserLocation(), cityNumber.get(u.getUserLocation()) + 1);
                            Collections.shuffle(favorites);//打乱增加随机性
                            int cnt = AppProperties.RECOMMEND_POST_NUM;//每个人最多提供推荐收藏帖子数量
                            for (Favorite favorite : favorites) {
                                if (!postIds.contains(favorite.getPostId())) {
                                    postIds.add(favorite.getPostId());
                                    cnt--;
                                }
                                if (cnt == 0) break;
                            }
                        }
                        //添加推荐用户喜欢的帖子id
                        List<Like> likes = likeMapper.selectList(new LambdaQueryWrapper<Like>().eq(Like::getUserId, user.getUserId()));
                        if (!likes.isEmpty()) {
                            Collections.shuffle(likes);//打乱增加随机性
                            int cnt = AppProperties.RECOMMEND_POST_NUM;//每个人最多提供推荐点赞帖子数量
                            for (Like like : likes) {
                                if (!postIds.contains(like.getPostId())) {
                                    postIds.add(like.getPostId());
                                    cnt--;
                                }
                                if (cnt == 0) break;
                            }
                        }
                        //添加推荐用户发布的帖子id
                        List<Post> posts1 = postMapper.selectList(new LambdaQueryWrapper<Post>().eq(Post::getUserId, user.getUserId()));
                        if (!posts1.isEmpty()) {
                            Collections.shuffle(posts1);//打乱增加随机性
                            int cnt = AppProperties.RECOMMEND_POST_NUM;//每个人最多提供推荐点赞帖子数量
                            for (Post post : posts1) {
                                if (!postIds.contains(post.getId())) {
                                    postIds.add(post.getId());
                                    cnt--;
                                }
                                if (cnt == 0) break;
                            }
                        }
                    }
                    if (postIds.size() > 100) break;
                }
            }

        if (postIds.size() < AppProperties.RECOMMEND_POST_NUM * 2)//如果帖子数量小于10个,启动基于城市的协同算法
        {
            for (User u : users) {
                if (u.getRoleId().equals(user.getRoleId())) {
                    List<Favorite> favorites =  favoriteMapper.selectList(new LambdaQueryWrapper<Favorite>().eq(Favorite::getUserId, u.getUserId()));
                    //添加推荐用户的收藏夹的帖子id
                    if (!favorites.isEmpty()) {
                        cityNumber.replace(u.getUserLocation(), cityNumber.get(u.getUserLocation()) + 1);
                        Collections.shuffle(favorites);//打乱增加随机性
                        int cnt = AppProperties.RECOMMEND_POST_NUM;//每个人最多提供推荐收藏帖子数量
                        for (Favorite favorite : favorites) {
                            if (!postIds.contains(favorite.getPostId())) {
                                postIds.add(favorite.getPostId());
                                cnt--;
                            }
                            if (cnt == 0) break;
                        }
                    }
                    //添加推荐用户喜欢的帖子id
                    List<Like> likes = likeMapper.selectList(new LambdaQueryWrapper<Like>().eq(Like::getUserId, user.getUserId()));
                    if (!likes.isEmpty()) {
                        Collections.shuffle(likes);//打乱增加随机性
                        int cnt = AppProperties.RECOMMEND_POST_NUM;//每个人最多提供推荐点赞帖子数量
                        for (Like like : likes) {
                            if (!postIds.contains(like.getId())) {
                                postIds.add(like.getId());
                                cnt--;
                            }
                            if (cnt == 0) break;
                        }
                    }
                    //添加推荐用户发布的帖子id
                    List<Post> posts1 = postMapper.selectList(new LambdaQueryWrapper<Post>().eq(Post::getUserId, user.getUserId()));
                    if (!posts1.isEmpty()) {
                        Collections.shuffle(posts1);//打乱增加随机性
                        int cnt = AppProperties.RECOMMEND_POST_NUM;//每个人最多提供推荐点赞帖子数量
                        for (Post post : posts1) {
                            if (!postIds.contains(post.getId())) {
                                postIds.add(post.getId());
                                cnt--;
                            }
                            if (cnt == 0) break;
                        }
                    }
                }
                if (postIds.size() > 100) break;
            }
        }
        if (postIds.size() < AppProperties.RECOMMEND_POST_NUM * 2)//如果帖子数量小于10个,启动基于语言的协同算法
        {
            for (User u : users) {
                if (u.getUserLang().equals(user.getUserLang())) {
                    List<Favorite> favorites =  favoriteMapper.selectList(new LambdaQueryWrapper<Favorite>().eq(Favorite::getUserId, u.getUserId()));
                    //添加推荐用户的收藏夹的帖子id
                    if (!favorites.isEmpty()) {
                        cityNumber.replace(u.getUserLocation(), cityNumber.get(u.getUserLocation()) + 1);
                        Collections.shuffle(favorites);//打乱增加随机性
                        int cnt = AppProperties.RECOMMEND_POST_NUM;//每个人最多提供推荐收藏帖子数量
                        for (Favorite favorite : favorites) {
                            if (!postIds.contains(favorite.getPostId())) {
                                postIds.add(favorite.getPostId());
                                cnt--;
                            }
                            if (cnt == 0) break;
                        }
                    }
                    //添加推荐用户喜欢的帖子id
                    List<Like> likes = likeMapper.selectList(new LambdaQueryWrapper<Like>().eq(Like::getUserId, user.getUserId()));
                    if (!likes.isEmpty()) {
                        Collections.shuffle(likes);//打乱增加随机性
                        int cnt = AppProperties.RECOMMEND_POST_NUM;//每个人最多提供推荐点赞帖子数量
                        for (Like like : likes) {
                            if (!postIds.contains(like.getId())) {
                                postIds.add(like.getId());
                                cnt--;
                            }
                            if (cnt == 0) break;
                        }
                    }
                    //添加推荐用户发布的帖子id
                    List<Post> posts1 = postMapper.selectList(new LambdaQueryWrapper<Post>().eq(Post::getUserId, user.getUserId()));
                    if (!posts1.isEmpty()) {
                        Collections.shuffle(posts1);//打乱增加随机性
                        int cnt = AppProperties.RECOMMEND_POST_NUM;//每个人最多提供推荐点赞帖子数量
                        for (Post post : posts1) {
                            if (!postIds.contains(post.getId())) {
                                postIds.add(post.getId());
                                cnt--;
                            }
                            if (cnt == 0) break;
                        }
                    }
                }
                if (postIds.size() > 100) break;
            }
        }
        if (postIds.size() < AppProperties.RECOMMEND_POST_NUM * 2) {
            List<Map<String, Object>> allPost = getAllPost(userId);
            int cnt = AppProperties.RECOMMEND_POST_NUM * 2 - postIds.size();
            for (Map<String, Object> post : allPost) {
                postIds.add((int) post.get("postId"));
                cnt--;
                if (cnt == 0) break;
            }
        }
        Collections.shuffle(postIds);//再次随机，增加随机性
        return postIds.subList(0, AppProperties.RECOMMEND_POST_NUM <= postIds.size() ? AppProperties.RECOMMEND_POST_NUM : postIds.size());//随机返回五个经过推荐的帖子
    }

    public List<Map<String, Object>> getAllPost(int userId) {
        List<Post> posts = postMapper.selectList(null);
        List<Map<String, Object>> datas = new ArrayList<>();
        for (Post post : posts) {
            Map<String, Object> result = new LinkedHashMap<>();
            User user = userMapper.selectById(post.getUserId());
            result = new LinkedHashMap<>();
            result.put("content", post.getContent());//帖子内容
            result.put("img", post.getImg());//帖子图片
            result.put("location", post.getLocation());//帖子定位
            result.put("friendId", post.getFriendId());//艾特好友id
            result.put("profilePic", userMapper.selectById(post.getUserId()).getProfilePic());//发布帖子用户的头像
            result.put("userId", post.getUserId());//发布帖子用户Id
            result.put("name", user.getNickname());//发布帖子用户名
            result.put("postId", post.getId());//帖子Id
            result.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(post.getPostTime()));//帖子发布时间
            result.put("likeNum", post.getLikeNum());//帖子点赞数
            result.put("isLike", likeMapper.selectCount(new LambdaQueryWrapper<Like>().eq(Like::getPostId, post.getId()).eq(Like::getUserId, userId)) != 0);//当前用户帖是否点赞帖子
            result.put("commentNum", commentMapper.selectCount(new LambdaQueryWrapper<Comment>().eq(Comment::getPostId, post.getId())));//帖子评论数
            Favorite favorite = new Favorite();
            favorite.setPostId(post.getId());
            favorite.setUserId(userId);
            result.put("isStaring", favoriteMapper.selectCount(new LambdaQueryWrapper<Favorite>().eq(Favorite::getPostId, favorite.getPostId()).eq(Favorite::getUserId, favorite.getUserId())) != 0);//当前用户是否收藏帖子
            datas.add(result);
        }
        return datas;
    }

    @Override
    public Map<String, Object> getPostById(int userId, int postId) throws PostNotExistException {
        List<Map<String, Object>> datas = getAllPost(userId);
        Map<String, Object> result = null;
        for (Map<String, Object> data : datas) {
            if ((int) data.get("postId") == postId) {
                result = data;
                break;
            }
        }
        if (result != null) {
            return result;
        } else {
            throw new PostNotExistException("帖子不存在");
        }
    }

    @Override
    @Transactional // 启用事务
    public int[] savePost(Post post) throws PostNotExistException {
        int[] result = {0, 0};
        post.setPostTime(new Timestamp(new Date().getTime()));
        User user = userMapper.selectById(post.getUserId());
        if (user.canPostInToday()) {
            user.PostIn();
            userMapper.updatePostDateByUserId(post.getUserId(),post.getPostTime());
            userMapper.updateIntegralOneByUserId(post.getUserId());
            result[1]=1;
        }
        try {
            if (BannedWordUtil.isBannedWord(post.getContent())) {
                throw new PubBannedWordsException("帖子内容不合法");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        if (post.getContent() == null || post.getContent().isEmpty()) {
            result[0]=-1;//表示帖子内容为空
        }


        int count = postMapper.insert(post);

        // 自定义的异常必须继承RuntimeException才会被事务管理器回滚
        if (count == 0) {//为0表示添加事务出错
            throw new PostNotExistException("添加帖子失败");
        } else {
            List<Post> posts = postMapper.selectList(new LambdaQueryWrapper<Post>().eq(Post::getUserId, post.getUserId()));
            /**
             * 如果该用户是第一次发布帖子，则管理员会对其发送相关信息
             */
            if (posts.size() == 1) {
                Chat chat = new Chat();
                chat.setToUserId(post.getUserId());//发给第一次发帖的用户
                chat.setUserId(1);//用户id为1，即管理员账号，发起聊天
                chat.setContent("亲爱的" + userMapper.selectById(post.getUserId()).getNickname() + ":\n" +
                        "  你好呀！\n" +
                        "  欢迎来到SMP网络社区，您可以在这里发布您的日常生活，您的兴趣爱好，也可以查看其他用户所发布的帖子。\n" +
                        "  但是在本社区游玩的过程中，也需要遵守相关的规定。\n" +
                        "  规定如下:\n" +
                        "  1.帖子、评论内容禁止涉及黄赌毒\n" +
                        "  2.评论禁止引战\n" +
                        "  3.待后续补充\n" +
                        "  以上规则如有违反，社区将会对其进行封号处理！\n" +
                        "  祝您使用愉快，再见！");
                chat.setTime(new Timestamp(new Date().getTime()));
                chat.setIsRead(0);
                int cou = chatMapper.insert(chat);
                System.out.println(cou);
            }
            return result;
        }

    }

    @Override
    @Transactional // 启用事务
    public int deletePost(int postId) throws PostNotExistException {
        int count = 0;
        count = postMapper.deleteById(postId);
        if (count == 0) {
            throw new PostNotExistException("删除帖子失败");
        } else {
            return count;
        }
    }

    @Override
    public List<Map<String, Object>> getPostSelf(int userId, int nowUserId) throws PostNotExistException {
        List<Map<String, Object>> datas = getAllPost(nowUserId);
        List<Map<String, Object>> results = new ArrayList<>();
        for (Map<String, Object> data : datas) {
            if ((int) data.get("userId") == userId) {
                results.add(data);
            }
        }
        if (results.isEmpty()) {
            throw new PostNotExistException("该用户没有发布帖子");
        }
        return results;
    }

    @Override
    public List<Map<String, Object>> getPostSelfFollow(int userId) throws PostNotExistException {
        List<Map<String, Object>> datas = getAllPost(userId);
        //获取当前用户关注用户id列表
        List<User> Follows = followMapper.selectByFollowerUserId(userId);
        List<Integer> followIds = new ArrayList<>();
        Follows.forEach(follow -> {
            followIds.add(follow.getUserId());
        });
        List<Integer> recommendPostIds = userCF(userId);
        List<Map<String, Object>> finalPosts = new ArrayList<>();
        for (Map<String, Object> data : datas) {
            if (followIds.contains(data.get("userId")) || (int) data.get("userId") == userId || recommendPostIds.contains((int) data.get("postId"))) {//如果是当前用户关注用户或者是当前用户发布的帖子或者是经过推荐算法推荐的帖子则加入最终返回列表
                finalPosts.add(data);
            }
        }
        return finalPosts;
    }

}




